using System;
using System.Activities.Statements;
using System.Collections.Generic;
using System.Text;
using Headsight.BPMN2WF.BPMN;
using Headsight.BPMN2WF.BPMN.BlockModel;
using Headsight.BPMN2WF.BPMN.Model;
using Headsight.BPMN2WF.BPMN.Schemas;
using Headsight.BPMN2WF.BPMN.Utils;
using Headsight.BPMN2WF.Testing.TestObjCtors;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace Headsight.BPMN2WF.Utils
{
    [TestClass]
    public class ExtensionsTest
    {
        [TestMethod]
        public void ForEach_in_case_of_empty_IEnumerable()
        {
            var enumerable = (IEnumerable<Object>)new object[0];

            enumerable.ForEach(x => Assert.Fail("**failed**"));
        }

        [TestMethod]
        public void ForEach()
        {
            var enumerable = (IEnumerable<String>)new[] { "Hello", " ", "World" };

            var sb = new StringBuilder();
            enumerable.ForEach(x => sb.Append(x));

            Assert.AreEqual("Hello World", sb.ToString());
        }

        [TestMethod]
        public void ToFlowStep_inco_Activity()
        {
            var activity = new If();
            var actual = ((Object)activity).ToFlowStep() as FlowStep;

            Assert.IsNotNull(actual);
            Assert.AreSame(activity, actual.Action);
        }

        [TestMethod]
        public void ToFlowStep_inco_Flowchart()
        {
            var flowchart = new Flowchart();

            var actual = flowchart.ToFlowStep() as FlowStep;

            Assert.IsNotNull(actual);
            Assert.AreSame(flowchart, actual.Action);
        }

        [TestMethod]
        public void ToFlowStep_inco_FlowStep()
        {
            var flowStep = new FlowStep();

            Assert.AreSame(flowStep, ((Object)flowStep).ToFlowStep());
        }

        private static void PerformTest_GetExpressionIdAndExpression(String expectedId, String expectedExpression, tExpression expression, string elementId, string name)
        {
            var gateway = new BPMNFlowNodeCtor().WithId("idGateway").Create();
            var element = new BPMNFlowNodeCtor().WithId(elementId).Create();
            element.TElement.name = name;
            var seqFlow = new BPMNSequenceFlowCtor().WithId("id1").WithFlowFrom(gateway.TElement).WithFlowTo(element.TElement).Create();

            var bpmnProcess = new BPMNProcessCtor().With(gateway, element).With(seqFlow).Create();

            seqFlow.TElement.conditionExpression = expression;

            var result = bpmnProcess.GetExpressionIdAndExpression(gateway, element);

            Assert.AreEqual(expectedId, result.Item1);
            Assert.AreEqual(expectedExpression, result.Item2);
        }

        [TestMethod]
        public void GetExpressionIdAndExpression_inco_conditionExpression_is_null()
        {
            PerformTest_GetExpressionIdAndExpression("idElement", "<empty conditionExpression>", null, "idElement", null);
        }

        [TestMethod]
        public void GetExpressionIdAndExpression_inco_conditionExpression_Text_is_null()
        {
            PerformTest_GetExpressionIdAndExpression("idElement", "<empty conditionExpression>", new tExpression(), "idElement", null);
        }

        [TestMethod]
        public void GetExpressionIdAndExpression_inco_conditionExpression_Text_is_empty()
        {
            PerformTest_GetExpressionIdAndExpression("idElement", "<empty conditionExpression>", new tExpression() { Text = new String[0]}, "idElement", null);
        }

        [TestMethod]
        public void GetExpressionIdAndExpression_inco_conditionExpression_Text()
        {
            PerformTest_GetExpressionIdAndExpression("idElement", "hello world expression text", new tExpression() { Text = new [] { "hello world expression text"} }, "idElement", null);
        }

        [TestMethod]
        public void GetExpressionIdAndExpression_inco_conditionExpression_Text_has_2_or_more_elements()
        {
            PerformTest_GetExpressionIdAndExpression("idElement", "line1line2", new tExpression() { Text = new[] { "line1", "line2" } }, "idElement", null);
        }

        [TestMethod]
        public void GetExpressionIdAndExpression_inco_conditionExpression_Text_has_new_lines()
        {
            PerformTest_GetExpressionIdAndExpression("idElement", "line1line2", new tExpression() { Text = new[] { "l\r\nin\re1\n", "l\n\rine2" } }, "idElement", null);
        }

        [TestMethod]
        public void GetExpressionIdAndExpression_verify_expressionId_inco_name_set()
        {
            PerformTest_GetExpressionIdAndExpression("nonNullName (id: idElement)", "<empty conditionExpression>", new tExpression(), "idElement", "nonNullName");
        }

        private static void PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_existing(Type tGatewayType, String defaultBranchId)
        {
            dynamic tGateway = Activator.CreateInstance(tGatewayType);
            tGateway.@default = defaultBranchId;

            var gateway = new BPMNFlowNodeCtor().WithTFlowElement((tGateway)tGateway).Create();
            var defaultElement = new BPMNFlowNodeCtor().Create();
            var otherBranch = new BPMNFlowNodeCtor().Create();
            var seqFlow1 = new BPMNSequenceFlowCtor().WithId(defaultBranchId).WithFlowFrom(gateway.TElement).WithFlowTo(defaultElement.TElement).Create();
            var seqFlow2 = new BPMNSequenceFlowCtor().WithId("id1234").WithFlowFrom(gateway.TElement).WithFlowTo(otherBranch.TElement).Create();

            var bpmnProcess = new BPMNProcessCtor().With(gateway, defaultElement).With(seqFlow1).With(seqFlow2).Create();

            var result = bpmnProcess.GetDefaultBranch(gateway);

            Assert.AreEqual(true, bpmnProcess.HasDefaultBranch(gateway));
            Assert.AreSame(defaultElement, result);
            Assert.AreEqual(true, bpmnProcess.IsDefaultBranchOf(gateway, defaultElement));
            Assert.AreEqual(false, bpmnProcess.IsDefaultBranchOf(gateway, otherBranch));
        }

        private static void PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_not_existing(Type tGatewayType)
        {
            dynamic tGateway = Activator.CreateInstance(tGatewayType);
            tGateway.@default = null;

            var gateway = new BPMNFlowNodeCtor().WithTFlowElement((tGateway)tGateway).Create();
            var defaultElement = new BPMNFlowNodeCtor().WithId(null).Create();

            var bpmnProcess = new BPMNProcessCtor().With(gateway, defaultElement).Create();

            var result = bpmnProcess.GetDefaultBranch(gateway);

            Assert.AreEqual(false, bpmnProcess.HasDefaultBranch(gateway));
            Assert.AreEqual(null, result);
            Assert.AreEqual(false, bpmnProcess.IsDefaultBranchOf(gateway, defaultElement));
        }

        [TestMethod]
        public void HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_inco_tExclusiveGateway_inco_default_branch_existing()
        {
            PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_existing(typeof(tExclusiveGateway), "id_of_tFlowElement_default");
        }

        [TestMethod]
        public void HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_inco_tExlusiveGateway_inco_default_branch_not_existing()
        {
            PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_not_existing(typeof(tExclusiveGateway));
        }

        [TestMethod]
        public void HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_inco_tInclusiveGateway_inco_default_branch_existing()
        {
            PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_existing(typeof(tInclusiveGateway), "id_of_tFlowElement_default");
        }

        [TestMethod]
        public void HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_inco_tInclusiveGateway_inco_default_branch_not_existing()
        {
            PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_not_existing(typeof(tInclusiveGateway));
        }

        [TestMethod]
        public void HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_inco_tComplexGateway_inco_default_branch_existing()
        {
            PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_existing(typeof(tComplexGateway), "id_of_tFlowElement_default");
        }

        [TestMethod]
        public void HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_inco_tComplexGateway_inco_default_branch_not_existing()
        {
            PerformTest_HasDefaultBranch_GetDefaultBranch_IsDefaultBranchOf_not_existing(typeof(tComplexGateway));
        }

        [TestMethod]
        public void BPMNFlowNodeOrNodeIn_inco_BPMNProcessBlock()
        {
            var expected = new BPMNFlowNodeCtor().Create();
            var processBock = new BPMNFlowNodesBlock(expected);

            Assert.AreSame(expected, processBock.BPMNFlowNodeOrNodeIn());
        }

        [TestMethod]
        public void BPMNFlowNodeOrNodeIn_inco_BPMNFlowNode()
        {
            var expected = new BPMNFlowNodeCtor().Create();

            Assert.AreSame(expected, expected.BPMNFlowNodeOrNodeIn());
        }
    }
}